   //
//  RequestManager+BK.m
//  bestkeep
//
//  Created by 武探 on 2016/11/14.
//  Copyright © 2016年 utouu. All rights reserved.
//

#import "RequestManager+BK.h"
#import "Mediator+BKMy.h"
#import "MJExtension.h"

#define BKDataRequestTimeOut 8

NSString *const BKErrorDomain = @"com.utouu.bestkeep";

@implementation RequestManager (BK)

-(NSString*)bkCurrentTime {
    NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0];
    long long a=[dat timeIntervalSince1970]*1000;
    NSString *timeString = [NSString stringWithFormat:@"%lld", a];
    return timeString;
}

-(NSInteger)bkCurrentWeekday{
    NSInteger week;
    int weekOfDays[7] = {7,1,2,3,4,5,6};
    NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0];
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier: NSCalendarIdentifierGregorian];
    NSTimeZone *timeZone = [[NSTimeZone alloc] initWithName:@"Asia/Shanghai"];
    [calendar setTimeZone: timeZone];
    NSCalendarUnit calendarUnit = NSCalendarUnitWeekday;
    NSDateComponents *theComponents = [calendar components:calendarUnit fromDate:dat];
    week = [theComponents weekday]-1;
    if (week < 0) {
        week = 0;
    }
    
    return weekOfDays[week];
}

//系统时间格式化
-(NSString*)timeFormat:(NSString*)time {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    NSDate *date = [[NSDate alloc]initWithTimeIntervalSince1970:[time longLongValue]/1000.0];
    return [NSString stringWithFormat:@"%@", [dateFormatter stringFromDate:date]];
}

//获取索引值
-(NSInteger)bkDynamicIndex:(NSString*)time timeStamp:(NSString*)timestamp{
    
    NSInteger week = (double)[self bkCurrentWeekday] ;
    
    long long d = [timestamp doubleValue];
    NSInteger index = d % week;
    if (index == 0) {
        index =7;
    }
    
    index =(32-index);
    
    return index;
}

//获取动态字典
-(NSDictionary *)bkDynamicValues:(NSString*)time md5Sign:(NSString*)md5Sign{
    NSInteger dyNamicIndex = [self bkDynamicIndex:[self timeFormat:time] timeStamp:time];
    NSString *str = [NSString stringWithFormat:@"%@%@",md5Sign,time];
    md5Sign = [str MD5String];
    NSString *stringValue = [md5Sign substringFromIndex:dyNamicIndex];
    NSString *md5Time = [time MD5String];
    NSString *stringKey = [md5Time substringFromIndex:dyNamicIndex];
    NSMutableDictionary *kv = [NSMutableDictionary new];
    [kv setValue:stringValue forKey:stringKey];
    return kv;
}

-(NSString*)bkMD5FromParameters:(NSDictionary<NSString*, id>*)parameters {
    NSArray *keys = [parameters allKeys];
    //key值按升序排列
    NSArray *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        return [obj1 compare:obj2];
    }];
    
    NSMutableString *MD5String = [NSMutableString stringWithString:@""];
    for (NSString *key in sortedKeys) {
        NSString *value = [NSString stringWithFormat:@"%@", parameters[key]];
        if (![key isEqualToString:@""] && ![key isEqualToString:@"sign"] && ![key isEqualToString:@"time"]) {
            [MD5String appendString:value];
        }
    }

    return [NSString stringWithString:MD5String];
}

//返回签名
-(NSString*)bkSignWithTime:(NSString*)time parameters:(NSDictionary<NSString*, id>*)parameters {
    NSString *md5Sign = [self bkMD5FromParameters:parameters];
    NSDictionary *dict = [self bkDynamicValues:time md5Sign:md5Sign];
    for (NSString *key in dict) {
        if ([key length] <=7 && [dict[key] length] <=7) {
            
            return [[key stringByAppendingString:dict[key]] MD5String];
        }
    }

    return nil;
}

-(NSDictionary*)bkHeaderContexts:(NSDictionary<NSString*, id>*)parameters validateURL:(NSString*)validateURL {
    
    //时间
    NSString *time = [self bkCurrentTime];
    
    //生成sign
    NSString *sign = [self bkSignWithTime:time parameters:parameters];
    
    NSMutableDictionary *head_dic = [[NSMutableDictionary alloc] initWithCapacity:5];
    NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary];
    NSString* versionNum =[infoDict objectForKey:@"CFBundleVersion"];
    NSString *version = [NSString stringWithFormat:@"%@.%@",[infoDict objectForKey:@"CFBundleShortVersionString"],versionNum];
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey];
    if (appName == nil) {
        appName =@"";
    }
    
    NSString *deviceModel = [[UIDevice currentDevice] model];
    NSString *deviceSys = [[UIDevice currentDevice] systemVersion];
    CGFloat screenScale = [[UIScreen mainScreen] scale];
    NSString *user_agent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)",appName,version,deviceModel,deviceSys,screenScale];
    [head_dic setObject:sign forKey:@"cas-client-sign"];
    [head_dic setObject:time forKey:@"cas-client-time"];
    [head_dic setObject:user_agent forKey:@"User-Agent"];
    
    NSURL *vURL = [NSURL URLWithString:validateURL];
    NSString *urlString = [NSString stringWithFormat:@"%@://%@", [vURL scheme], [vURL host]];
    
    [head_dic setObject:urlString forKey:@"cas-client-service"];
    
    NSDictionary *userInfo = [[Mediator sharedInstance] BKMyUserInfo];
    NSString *loginST = userInfo[BKMyUserGetUTOUUPlatformSTkey];
    if (loginST == nil) {
        
        loginST = @"";
    }
    [head_dic setObject:loginST forKey:@"cas-client-st"];
//    NSString *serviceST = userInfo[BKMyUserGetBestKeepPlateformSTKey];
    
//    if([vURL.host rangeOfString:@"utouu.com"].length > 0) {
//        [head_dic setObject:loginST forKey:@"cas-client-st"];
//    } else {
//        [head_dic setObject:serviceST forKey:@"cas-client-st"];
//    }
    
    return head_dic;
}

-(void)bkDataRequest:(RequestMethod)method URLString:(NSString*)URLString parameters:(NSDictionary<NSString*, id>*)parameters success:(void (^)(id responseObject))success failure:(void(^)(id responseObject, NSError *error))failure {
    NSMutableString *body = [[NSMutableString alloc]init];;
    for(NSString *key in [parameters allKeys]){
        NSString *value= [parameters objectForKey:key];
        [body appendString:[NSString stringWithFormat:@"%@=%@&",key,value]];
    }
    //1 pc（默认） 2.Android   3.ios
    [body appendString:[NSString stringWithFormat:@"source_code=3"]];
    NSLog(@"\n\n\n[-------Send------]:%@?%@\n\n\n",URLString,body);
    
    
    NSError *exError;
    NSMutableURLRequest *request = [self HTTPRequestWithMethod:method URLString:URLString parameters:parameters error:&exError];
    if(exError) {
        failure(nil, exError);
        return;
    }
    
    request.timeoutInterval = BKDataRequestTimeOut;
    
    [self bkRequestHeaderFiledConfig:request parameters:parameters validateURL:URLString];
    
    [self dataWithRequest:request responseConfig:^id<AFURLResponseSerialization> _Nullable{
        
        AFHTTPResponseSerializer *serializer;
        if(parameters && [parameters.allKeys containsObject:@"service"]) {
            serializer = [AFHTTPResponseSerializer serializer];
        } else {
            serializer = [AFJSONResponseSerializer serializer];
            [serializer setAcceptableContentTypes:[NSSet setWithObjects:@"application/json",@"text/json",@"text/javascript",@"text/html",@"text/plain", nil]];
        }
        
        return serializer;
    } completionHandler:^(NSURLResponse * _Nullable response, id  _Nullable responseObject, NSError * _Nullable error) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
        NSString *jsonStr = [responseObject mj_JSONString];
        
         NSLog(@"\n\n\n[---POST----Result----%li--]:%@     --request.URL-->%@\n\n\n",(long)httpResponse.statusCode,jsonStr,httpResponse.URL);
        if(error) {
            
            if(httpResponse.statusCode == 502 && error.userInfo[@"NSUnderlyingError"] != nil) {

                
//                NSError * bk_error=[NSError errorWithDomain:error.domain code:error.code userInfo:error.userInfo];
//                
//                bk_error.localizedDescription=@"";
                
                failure(responseObject, error.userInfo[@"NSUnderlyingError"]);
            } else {
                failure(responseObject, error);
            }
        } else {
            
            [[RequestManager manager] bkErrorFilter:URLString data:responseObject success:success retryReady:^(NSString *ST) {
                
                [[RequestManager manager] bkDataRequest:method URLString:URLString parameters:parameters success:success failure:failure];
            } failure:failure];
        }
        
    }];
}

-(void)bkUploadRequest:(RequestMethod)method URLString:(NSString*)URLString parameters:(NSDictionary<NSString*, id>*)parameters file:(BKFileObject*)file success:(void (^)(id responseObject))success failure:(void(^)(id responseObject, NSError *error))failure {
    
    [self bkUploadRequest:method URLString:URLString parameters:parameters files:@[file] progress:nil success:success failure:failure];
    
}

-(void)bkUploadRequest:(RequestMethod)method URLString:(NSString*)URLString parameters:(NSDictionary<NSString*, id>*)parameters file:(BKFileObject*)file progress:(void (^)(int64_t totalUnitCount, int64_t completedUnitCount))progress success:(void (^)(id responseObject))success failure:(void(^)(id responseObject, NSError *error))failure {
    
    [self bkUploadRequest:method URLString:URLString parameters:parameters files:@[file] progress:progress success:success failure:failure];
    
}

-(void)bkUploadRequest:(RequestMethod)method URLString:(NSString*)URLString parameters:(NSDictionary<NSString*, id>*)parameters files:(NSArray<BKFileObject*>*)files progress:(void (^)(int64_t totalUnitCount, int64_t completedUnitCount))progress success:(void (^)(id responseObject))success failure:(void(^)(id responseObject, NSError *error))failure {
    
    if(!files || files.count == 0) {
        NSString *localizedDescription = @"参数：<files> 不允许为空";
        NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: localizedDescription, NSLocalizedFailureReasonErrorKey: localizedDescription};
        failure(nil, [NSError errorWithDomain:BKErrorDomain code:-299 userInfo:errorInfo]);
        return;
    }
    
    NSError *exError;
    NSMutableURLRequest *request = [self multipartFormRequestWithMethod:method URLString:URLString parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        
        for (BKFileObject *file in files) {
            [formData appendPartWithFileData:file.data name:file.name fileName:file.fileName mimeType:file.mimeType];
        }
        
    } error:&exError];
    
    if(exError) {
        failure(nil, exError);
        return;
    }
    
    [self bkRequestHeaderFiledConfig:request parameters:parameters validateURL:URLString];
    
    [self uploadWithStreamedRequest:request progress:^(NSProgress * _Nonnull uploadProgress) {
        if(progress) {
            progress(uploadProgress.totalUnitCount, uploadProgress.completedUnitCount);
        }
        
    } completionHandler:^(NSURLResponse * _Nullable response, id  _Nullable responseObject, NSError * _Nullable error) {
        if(error) {
            failure(responseObject, error);
        } else {
            [[RequestManager manager] bkErrorFilter:URLString data:responseObject success:success retryReady:^(NSString *ST) {
                
                [[RequestManager manager] bkUploadRequest:method URLString:URLString parameters:parameters files:files progress:progress success:success failure:failure];
                
            } failure:failure];

        }
    }];
}

-(void)bkRequestHeaderFiledConfig:(NSMutableURLRequest*)request parameters:(NSDictionary*)parameters validateURL:(NSString*)validateURL {
    
    NSDictionary *headerFields = [self bkHeaderContexts:parameters validateURL:validateURL];
    for (NSString *key in headerFields) {
        [request setValue:headerFields[key] forHTTPHeaderField:key];
    }
}

/**
 验证返回数据是否可用 （主要判断令牌失效的情况,其他交由调用者去处理）
 */
-(void)bkErrorFilter:(NSString*)URLString data:(id)responseObject success:(void (^)(id responseObject))success retryReady:(void(^)(NSString *ST))retryReady failure:(void(^)(id responseObject, NSError *error))failure {
    if(![responseObject isKindOfClass:[NSDictionary class]]) {
        success(responseObject);
        return;
    }
    
    id codeValue = responseObject[@"code"];
//    if(!codeValue && ![codeValue isEqual:[NSNull null]] ) {
//        success(responseObject);
//        return;
//    }
    
    if(!codeValue || [codeValue isEqual:[NSNull null]] || [codeValue isEqualToString:@""]) {
        success(responseObject);
        return;
    }
    
    NSString *code = [NSString stringWithFormat:@"%@", codeValue];
    if([code isEqualToString:@"023"]) {
        [[Mediator sharedInstance] userLoginOut];
    } else if([code isEqualToString:@"025"]) { //令牌失效
        NSURL *vURL = [NSURL URLWithString:URLString];
        NSString *urlString = [NSString stringWithFormat:@"%@://%@", [vURL scheme], [vURL host]];
        
        [[Mediator sharedInstance] getSTWithServerce:urlString compeleteBlock:^(id obj, id inform, NSError *error) {
            if(error) {
                failure(nil, error);
            } else {
                retryReady(inform);
            }
        }];
        
    } else if([code isEqualToString:@"030"]) { //非法请求
        NSString *msg = responseObject[@"msg"];
        [HUD showErrorMessage:msg];
    }
//        else if([codeValue isEqualToString:@"020"]) {
//        NSString *localizedDescription = @"程序异常";
//        NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: localizedDescription, NSLocalizedFailureReasonErrorKey: localizedDescription};
//        NSError *cuError = [NSError errorWithDomain:BKErrorDomain code:-200 userInfo:errorInfo];
//        
//        failure(responseObject, cuError);
//    }
    else {
        success(responseObject);
    }
    
}

@end
